<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <title>绚丽的烟花</title>
    <meta name="viewport" content="initial-scale=1, maximum-scale=1">
    <meta name="apple-mobile-web-app-capable" content="yes">
    <meta name="apple-mobile-web-app-status-bar-style" content="black">
</head>
<style type="text/css">
    * {
        margin: 0;
        padding: 0;
    }
    
    body {
        overflow: hidden;
    }
    
    canvas {
        background: #000;
    }
</style>

<body>
    <canvas id="canvas">你的浏览器太low啦</canvas>
</body>
<script type="text/javascript">
    (function(win, el) {
        var canvas = document.querySelector(el),
            ctx = canvas.getContext('2d');
        canvas.width = win.innerWidth;
        canvas.height = win.innerHeight;

        var config = { //基础配置
            circleArr: [], //鼠标圆圈
            lineArr: [], //烟花射线
            boomArr: [], //烟花散射点
            curHue: 170, //基础颜色值
            curBrightness: rand(50, 80)
        };
        var mouse = {
            x: canvas.width / 2,
            y: canvas.height / 2,
            status: 3 //鼠标状态1（mousedown）2（mousemove）3（mouseup）
        }

        function rand(min, max) { //获取随机数
            if (arguments.length < 2) {
                var max = min;
                return Math.random() * max;
            } else {
                return Math.random() * (max - min) + min;
            }
        }
        // 鼠标圆圈
        function Circle(x, y) {
            this.x = x;
            this.y = y;
            this.r = 5;
            this.vr = 0.5;
            this.hue = config.curHue;
            this.brightness = rand(40, 60);
        }
        Circle.prototype.draw = function() {
            ctx.beginPath();
            ctx.lineWidth = 1;
            ctx.strokeStyle = 'hsla(' + this.hue + ', 100%, ' + this.brightness + '%, 1)';
            ctx.shadowBlur = 1;
            ctx.shadowColor = 'white';
            ctx.arc(this.x, this.y, this.r, 0, 2 * Math.PI);
            ctx.stroke();
        }

        function createCircle(x, y) {
            config.circleArr.push(new Circle(x, y))
        }

        function deleteCircle() {
            config.circleArr.shift()
        }

        function animateCircle() {
            for (var i = 0; i < config.circleArr.length; i++) {
                if (config.circleArr[i].r >= 15) {
                    config.circleArr[i].r = 5;
                }
                config.circleArr[i].r += config.circleArr[i].vr;
            };
        }

        function drawCircle() {
            for (var i = 0; i < config.circleArr.length; i++) {
                config.circleArr[i].draw();
            };
        }
        // 烟花射线
        function Line(sx, sy, tx, ty, hue) {
            this.sx = sx; //起点x
            this.sy = sy; //起点y
            this.cx = sx; //当前x
            this.cy = sy; //当前y
            this.tx = tx; //目标x
            this.ty = ty; //目标y

            this.r = 20;
            this.bl = (ty - sy) / (tx - sx); //斜率

            this.angle = Math.atan(Math.abs(ty - sy) / (tx - sx)); //角度
            this.ex = this.angle > 0 ? (this.cx + Math.cos(this.angle) * this.r) : (this.cx - Math.cos(this.angle) * this.r); //当前线终点x
            this.ey = this.cy - Math.abs(Math.sin(this.angle) * this.r); //当前线终点y

            this.animateEnd = false; //判断是否运动中

            this.speed = 50; //速度
            this.hue = hue; //颜色
            this.brightness = rand(40, 60); //亮度
            // console.log(this.angle)
        }
        Line.prototype.draw = function() {
            ctx.beginPath();
            ctx.shadowBlur = 0;
            ctx.lineWidth = 3;
            ctx.strokeStyle = 'hsla(' + this.hue + ', 100%, ' + this.brightness + '%, 1)';
            ctx.lineCap = 'round';
            ctx.moveTo(this.cx, this.cy);
            ctx.lineTo(this.ex, this.ey);
            ctx.stroke();

        }

        function createLine(sx, sy, ex, ey, hue) {
            config.lineArr.push(new Line(sx, sy, ex, ey, hue))
        }

        function animateLine() {
            for (var i = 0; i < config.lineArr.length; i++) {
                if (config.lineArr[i].animateEnd) continue;
                config.lineArr[i].cx += (config.lineArr[i].tx - config.lineArr[i].sx) / 40;
                config.lineArr[i].cy = config.lineArr[i].bl * (config.lineArr[i].cx - config.lineArr[i].sx) + config.lineArr[i].sy;

                if (config.lineArr[i].ey <= config.lineArr[i].ty) {
                    config.lineArr[i].ex = config.lineArr[i].tx;
                    config.lineArr[i].ey = config.lineArr[i].ty;
                    if (config.lineArr[i].cy <= config.lineArr[i].ty) {
                        deleteCircle();
                        createBoom(config.lineArr[i].tx, config.lineArr[i].ty, config.lineArr[i].hue);
                        config.lineArr.splice(i, 1);
                        i--;
                    }
                } else {
                    config.lineArr[i].ex += (config.lineArr[i].tx - config.lineArr[i].sx) / 40;
                    config.lineArr[i].ey = config.lineArr[i].bl * (config.lineArr[i].ex - config.lineArr[i].sx) + config.lineArr[i].sy;
                }
            };
        }

        function drawLine() {
            for (var i = 0; i < config.lineArr.length; i++) {
                config.lineArr[i].draw()
            };
        }
        // 烟花散射点
        function Boom(x, y, hue) {
            this.x = x;
            this.y = y;
            this.vx = rand(-5, 5);
            this.vy = rand(-5, 5);
            this.r = rand(1, 3);
            this.alpha = 1;
            this.hue = hue;
            this.brightness = rand(50, 80);
            this.alpha = 1;
            this.gravity = 0.05; //重力系数
        }
        Boom.prototype.draw = function() {
            ctx.beginPath();
            ctx.fillStyle = 'hsla(' + this.hue + ', 100%, ' + this.brightness + '%, ' + this.alpha + ')';
            ctx.shadowBlur = 0;
            ctx.lineWidth = 1;
            ctx.arc(this.x, this.y, this.r, 0, 2 * Math.PI);
            ctx.fill();
        }

        function createBoom(x, y, color) {
            for (var i = 0; i < 20; i++) {
                config.boomArr.push(new Boom(x, y, color));
            };
        }

        function animateBoom(x, y) {
            for (var i = 0; i < config.boomArr.length; i++) {
                config.boomArr[i].alpha -= 0.02;
                config.boomArr[i].vy += config.boomArr[i].gravity;
                config.boomArr[i].x += config.boomArr[i].vx;
                config.boomArr[i].y += config.boomArr[i].vy;
                if (config.boomArr[i].alpha <= 0.05) {
                    config.boomArr.splice(i, 1);
                    i--;
                };
            };
        }

        function drawBoom(x, y) {
            for (var i = 0; i < config.boomArr.length; i++) {
                config.boomArr[i].draw();
            };
        }

        function animate() {
            ctx.fillStyle = 'rgba(0,0,0,0.3)';
            // ctx.clearRect(0,0,canvas.width,canvas.height);
            ctx.fillRect(0, 0, canvas.width, canvas.height);

            animateCircle();
            drawCircle();

            animateLine();
            drawLine();

            animateBoom();
            drawBoom();
            if (config.lineArr.length == 0) config.circleArr.length = 0;
            requestAnimationFrame(animate);
        }
        var t;

        function init() { //开始创建一些烟花
            mouse.x = rand(100, canvas.width - 100);
            mouse.y = rand(0, canvas.height - 100);
            config.curHue = rand(0, 360);
            createCircle(mouse.x, mouse.y);
            createLine(canvas.width / 2, canvas.height, mouse.x, mouse.y, config.curHue)
            t = setTimeout(init, 100);
        }
        init()
        canvas.addEventListener('mousedown', function(e) {
            mouse.x = e.pageX;
            mouse.y = e.pageY;
            clearTimeout(t)
            config.curHue = rand(0, 360);
            createCircle(mouse.x, mouse.y);
            createLine(canvas.width / 2, canvas.height, mouse.x, mouse.y, config.curHue)
            mouse.status = 1;
        })
        canvas.addEventListener('mousemove', function(e) {
            mouse.x = e.pageX;
            mouse.y = e.pageY;
            if (mouse.status == 1) {
                // config.curHue = rand(0,360);
                createCircle(mouse.x, mouse.y);
                createLine(canvas.width / 2, canvas.height, mouse.x, mouse.y, config.curHue)
            }
        })
        canvas.addEventListener('mouseup', function(e) {
            mouse.x = e.pageX;
            mouse.y = e.pageY;
            mouse.status = 3;
        })
        requestAnimationFrame(animate);
    })(window, '#canvas')
</script>

</html>